package cn.neusoft.service.impl;

import cn.neusoft.domain.Warehouse;
import cn.neusoft.domain.*;
import cn.neusoft.enums.*;
import cn.neusoft.exception.AppException;
import cn.neusoft.exception.AppExceptionCodeMsg;
import cn.neusoft.feignClients.OrderFeignClient;
import cn.neusoft.mapper.AllocationMapper;
import cn.neusoft.mapper.StrategyMapper;
import cn.neusoft.mapper.TaskMapper;
import cn.neusoft.query.AllocationQuery;
import cn.neusoft.query.BaseQuery;
import cn.neusoft.query.OrderQuery;
import cn.neusoft.service.AllocationService;
import cn.neusoft.service.TaskService;
import cn.neusoft.util.BaiduMapUtils;
import cn.neusoft.util.EnumUtils;
import cn.neusoft.util.ExceptionUtils;
import cn.neusoft.util.UUIDUtils;
import cn.neusoft.vo.PageBean;
import cn.neusoft.vo.ResultBean;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    TaskMapper taskMapper;

    @Autowired
    StrategyMapper strategyMapper;

    @Autowired
    OrderFeignClient orderFeignClient;

    @Autowired
    AllocationService allocationService;

    @Autowired
    AllocationMapper allocationMapper;

    @Transactional
    @Override
    public String add(Task task) {

        // 配送费 <= 0
        if (task.getDelivery_fee().compareTo(BigDecimal.ZERO) <= 0) {
            throw new AppException(AppExceptionCodeMsg.TASK_DELIVERY_FEE_INVALID);
        }

//        // 任务单类型非法
//        if (!EnumUtils.isInclude(TaskType.class, task.getTask_type())) {
//            throw new AppException(AppExceptionCodeMsg.TASK_TYPE_INVALID);
//        }

        OrderQuery query = new OrderQuery();
        query.setOrder_id(task.getOrder_id());
        query.setOrder_kind(task.getOrder_kind());
        // 订单状态必须是可分配
        query.setOrder_status(OrderStatus.ASSIGNABLE.getCode());

        // 通过openfeign向客服中心发请求
        ResultBean<Order1> resultBean = orderFeignClient.findOrderByCondition(query);

        // 如果有错误，则抛出
        ExceptionUtils.throwOriginalException(resultBean);

        // 得到返回的数据
        Order1 order = resultBean.getData();

        // 找不到对应id的可分配订单
        if (order == null) {
            throw new AppException(AppExceptionCodeMsg.TASK_ORDER_ASSIGNABLE_CANNOT_FIND);
        }

        // 赋值给task
        copyOrderToTask(order, task);

        String task_id = UUIDUtils.getUUID();
        task.setTask_id(task_id);

        taskMapper.add(task);

        // 将订单状态置为已调度
        order.setOrder_status(OrderStatus.SCHEDULED.getCode());
        ResultBean resultBean1 = orderFeignClient.updateOrderStatus(order);

        // 有错误则抛出
        ExceptionUtils.throwOriginalException(resultBean1);

        return task_id;
    }

    @Transactional
    @Override
    public void deleteById(String task_id) {

    }

    @Transactional
    @Override
    public void update(Task task) {
        // 配送费 <= 0
        if (task.getDelivery_fee().compareTo(BigDecimal.ZERO) <= 0) {
            throw new AppException(AppExceptionCodeMsg.TASK_DELIVERY_FEE_INVALID);
        }

        Task task1 = taskMapper.findById(task.getTask_id());
        Integer taskType = task1.getTask_type();
        Integer taskState = task1.getTask_state();

        // 送货任务单
        if (Objects.equals(taskType, TaskType.DELIVERY.getCode())) {
            // 送货任务单只有状态为已调度才可以修改
            if (!Objects.equals(taskState, TaskState.SCHEDULED.getCode())) {
                throw new AppException(AppExceptionCodeMsg.TASK_CANNOT_UPDATE);
            }
        } else if (Objects.equals(taskType, TaskType.RETURN.getCode())) { // 退货任务单
            // 退货任务单只有状态为可分配才可以修改
            if (!Objects.equals(taskState, TaskState.ASSIGNABLE.getCode())) {
                throw new AppException(AppExceptionCodeMsg.TASK_CANNOT_UPDATE);
            }
        } else if (Objects.equals(taskType, TaskType.EXCHANGE.getCode())) { // 换货任务单
            // 换货任务单只有状态为已调度才可以修改
            if (!Objects.equals(taskState, TaskState.SCHEDULED.getCode())) {
                throw new AppException(AppExceptionCodeMsg.TASK_CANNOT_UPDATE);
            }
        }

        Long substationId = task.getSubstation_id();
        Warehouse warehouse = taskMapper.findWarehouseBySubstationId(substationId);
        Long warehouseId = warehouse.getWarehouse_id();
        task1.setSubstation_id(substationId);
        task1.setWarehouse_id(warehouseId);
        task1.setDelivery_fee(task.getDelivery_fee());

        // 修改任务单
        taskMapper.update(task1);

        // 修改调拨单
        AllocationQuery query = new AllocationQuery();
        query.setTask_id(task1.getTask_id());
        List<Allocate> allocateList = allocationMapper.findByCondition(query);
        if (allocateList != null) {
            // 送货任务单
            if (Objects.equals(taskType, TaskType.DELIVERY.getCode())) {
                Allocate allocate = allocateList.get(0);
                allocate.setIn_id(warehouseId);
                allocationMapper.updateAllocate(allocate);
            } else if (Objects.equals(taskType, TaskType.RETURN.getCode())) { // 退货任务单
                Allocate allocate = allocateList.get(0);
                allocate.setIn_id(warehouseId);
                allocationMapper.updateAllocate(allocate);
            } else if (Objects.equals(taskType, TaskType.EXCHANGE.getCode())) { // 换货任务单
                List<Allocate> allocateList1 = allocateList
                        .stream()
                        .peek(item -> item.setIn_id(warehouseId))
                        .collect(Collectors.toList()
                        );
                allocateList1.forEach(allocate -> allocationMapper.updateAllocate(allocate));
            }
        }
    }

    @Transactional
    @Override
    public Task findById(String task_id) {
        return taskMapper.findById(task_id);
    }

    @Transactional
    @Override
    public List<Task> findAll() {
        return taskMapper.findAll();
    }

    @Transactional
    @Override
    public PageBean findByPage(BaseQuery query) {
        // 构建结果对象
        PageBean<Task> pageBean = new PageBean<>();

        // 开启分页
        PageHelper.startPage(query.getPageNow(), query.getPageSize());

        // 查询得到当前页的集合
        List<Task> taskList = taskMapper.findByCondition(query);

        // 创建一个分页的实体PageInfo
        PageInfo<Task> pageInfo = new PageInfo<>(taskList);

        pageBean.setTotalRows(pageInfo.getTotal());
        pageBean.setTotalPages(pageInfo.getPages());
        pageBean.setRowData(pageInfo.getList());

        return pageBean;
    }

    @Transactional
    @Override
    public void updateOrderStatus(Order order) {

    }

    /**
     * 调度：手动/自动
     *
     * @param query
     * @return
     * @throws Exception
     */
    @Transactional
    @Override
    public Map<String, Object> scheduling(BaseQuery query) throws Exception {


        // 通过openfeign向客服模块发送请求，得到订单信息
        ResultBean<Order1> resultBean = orderFeignClient.findOrderByCondition((OrderQuery) query);

        // 如果有错误，则抛出
        ExceptionUtils.throwOriginalException(resultBean);

        // 得到返回的数据
        Order1 order = resultBean.getData();

        // 找不到对应id的可分配订单
        if (order == null) {
            throw new AppException(AppExceptionCodeMsg.TASK_ORDER_ASSIGNABLE_CANNOT_FIND);
        }

        // 退货订单找原订单，取出地址赋值（神奇的设计，令人火大）
        if (Objects.equals(order.getOrder_kind(), OrderKind.RETURN.getCode())) {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setOrder_id(order.getOriginal_id());
            orderQuery.setOrder_kind(OrderKind.Normal.getCode());
            ResultBean<Order1> order1ResultBean = orderFeignClient.findOrderByCondition(orderQuery);
            ExceptionUtils.throwOriginalException(order1ResultBean);

            Order1 order1 = order1ResultBean.getData();
            if (order1 == null) {
                throw new AppException(AppExceptionCodeMsg.ORIGINAL_ORDER_NOT_EXITS);
            }

            order.setAddr(order1.getAddr());
        }

        // 根据订单中商品的数量，得到合适的备选分站
        List<Substation> fittingSubstations = taskMapper.findFittingSubstation(order.getAmount());

        System.out.println("fittingSubstations-----" + fittingSubstations);

        // 得到当前的调度策略
        Integer strategy = strategyMapper.getStrategy();

//        System.out.println("当前调度策略-----------" + strategy);

        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put("order", order);

        // 将substation转化为下拉列表的形式
        List<Map<String, Object>> substationSelect = fittingSubstations.stream()
                .map(substation -> {
                    // 创建每个子站点的对象
                    Map<String, Object> option = new HashMap<>();
                    option.put("value", substation.getSubstation_id());
                    option.put("label", substation.getSubstation_name());
                    return option;
                })
                .collect(Collectors.toList());

        returnMap.put("substationSelect", substationSelect);
        returnMap.put("substations", fittingSubstations);

        // 得到order中地址的编码
        String orderAddr = order.getAddr();
        String geoCoding = BaiduMapUtils.geoCoding(new LinkedHashMap<String, String>() {
            {
                put("address", orderAddr);
                put("output", "json");
            }
        });
        order.setCoordinate(geoCoding);

        // 手动调度
        if (Objects.equals(strategy, ScheduleStrategy.MANUAL.getCode())) {

            returnMap.put("best_substation_id", null);
            returnMap.put("warehouse", null);

        } else { // 自动调度

            // 构建批量算路所需的参数
            Map<String, String> params = new LinkedHashMap<>();
            String origins = fittingSubstations.stream()
                    .map(Substation::getCoordinate)
                    .collect(Collectors.joining("|"));
            System.out.println("批量算路参数: " + origins + "-----" + geoCoding);
            params.put("origins", origins);
            params.put("destinations", geoCoding);
            // 调用批量算路api
            int bestIndex = BaiduMapUtils.routeMatrix(params, strategy);

            Long bestSubstationId = fittingSubstations.get(bestIndex).getSubstation_id();
            System.out.println("最佳分站: " + fittingSubstations.get(bestIndex));
            Warehouse warehouse = taskMapper.findWarehouseBySubstationId(bestSubstationId);
            returnMap.put("best_substation_id", bestSubstationId);
            returnMap.put("warehouse", warehouse);
        }

        return returnMap;
    }

    @Transactional
    @Override
    public Warehouse findWarehouseBySubstationId(Long substation_id) {
        return taskMapper.findWarehouseBySubstationId(substation_id);
    }

    @Transactional
    @Override
    public List<Map<String, Object>> findFittingSubstation(Long amount) {
        List<Substation> substationList = taskMapper.findFittingSubstation(amount);

        // 将substation转化为下拉列表的形式
        List<Map<String, Object>> substationSelect = substationList.stream()
                .map(substation -> {
                    // 创建每个子站点的对象
                    Map<String, Object> option = new HashMap<>();
                    option.put("value", substation.getSubstation_id());
                    option.put("label", substation.getSubstation_name());
                    return option;
                })
                .collect(Collectors.toList());

        return substationSelect;
    }

    @Transactional
    @Override
    public void updateTask(Task task) {
        taskMapper.update(task);
    }

    @Transactional
    @Override
    public void entryTask(Task task) {
        Task task1 = new Task();
        task1.setTask_id(task.getTask_id());
        task1.setRemark(task.getRemark());
        task1.setTask_state(task.getTask_state());

        taskMapper.update(task1);
    }

    @Transactional
    @Override
    public void updateStrategy(Integer strategy) {

        // 策略非法
        if (!EnumUtils.isInclude(ScheduleStrategy.class, strategy)) {
            throw new AppException(AppExceptionCodeMsg.SCHEDULE_STRATEGY_INVALID);
        }

        strategyMapper.updateStrategy(strategy);
    }

    @Transactional
    @Override
    public Integer getStrategy() {
        return strategyMapper.getStrategy();
    }

    private void copyOrderToTask(Order1 order, Task task) {

        task.setCommodity_id(order.getOrder_commodity_id());
        task.setCommodity_name(order.getCommodity_name());
        task.setCustomer_id(order.getOrder_customer_id());
        task.setCustomer_name(order.getCustomer_name());
        task.setReceive_date(order.getDate());
        task.setReceive_addr(order.getAddr());
        task.setAmount(order.getAmount());
        task.setPrice(order.getPrice());

        Integer order_kind = order.getOrder_kind();
        if (Objects.equals(order_kind, OrderKind.Normal.getCode())) {
            task.setTask_type(TaskType.DELIVERY.getCode());
            // 送货任务单状态置为已调度，等分库到货后才是已分配
            task.setTask_state(TaskState.SCHEDULED.getCode());
        } else if (Objects.equals(order_kind, OrderKind.RETURN.getCode())) {
            task.setTask_type(TaskType.RETURN.getCode());
            // 退货任务单直接置为可分配
            task.setTask_state(TaskState.ASSIGNABLE.getCode());
        } else if (Objects.equals(order_kind, OrderKind.EXCHANGE.getCode())) {
            task.setTask_type(TaskType.EXCHANGE.getCode());
            // 换货单也设为已调度
            task.setTask_state(TaskState.SCHEDULED.getCode());
        }
    }
}